#ifndef HASH_CONTAINER_H
#define HASH_CONTAINER_H

#include "map_table.h"

/**
 * @class HashContainer
 * @note 哈析容器, 传入的key值，回调用key的成员函数genKeyValue生成哈析码，
 *  如果这个哈析码值不唯一，如key时字符类型，生成的哈析码，有极小的概率会生成
 *  同样的哈析码，而导致当插入的值会被替换掉。所以这个容器算法有一定的不稳定性，
 *  除非生成的哈析码是唯一值。也可以把传入的key直接用作MapTable的key，就可以解决这个问题.
 *  所以暂时定义两种方式实现这个类.
 * @warning 这个容器存储了value值，所以使用者必须确保value的内存不被释放，
 *  容器不管理内存（尤其是字符串，一定要确保字符串所在内存不 会在容器引用时期，被释放掉），否则将导致容器引用的是非法字符。
 */
template <typename _key, typename _value>
class HashContainer
{
public:
    HashContainer(int size)
        : mHash(new MapTable<unsigned, _value>[size])
        , mBucketLen(size)
    {
    }

    ~HashContainer()
    {
        delete [] mHash;
    }

    void clear()
    {
        for (int i = 0; i < mBucketLen; i++)
        {
            mHash[i].clear();
        }
    }

    void insert(_key const &key, _value const &val)
    {
        unsigned ikey  = key.genHashValue();
        unsigned index = ikey % mBucketLen;

        // 如果最大单链数量超过4个就必须重新排列hash表
        if (4 == mHash[index].size())
        {
            //GEN_Printf(LOG_WARN, "Need rearrange hash container.", mHash[index].size());
            re_create(mBucketLen * 1.3);
            index = ikey % mBucketLen;
        }

        mHash[index][ikey] = val;
    }

    bool remove(_key const &key)
    {
        unsigned ikey  = key.genHashValue();
        unsigned index = ikey % mBucketLen;

        return mHash[index].remove(ikey);
    }

    _value &operator[] (_key const &key)
    {
        unsigned ikey  = key.genHashValue();
        unsigned index = ikey % mBucketLen;

        // 如果最大单链数量超过4个就必须重新排列hash表
        if (4 == mHash[index].size())
        {
            re_create(mBucketLen << 1);
            index = ikey % mBucketLen;
        }

        return mHash[index][ikey];
    }

    MapTable<_key, _value> &at(int index)
    {
        return mHash[index];
    }

    int bucketLen() const
    {
        return mBucketLen;
    }
private:
    bool re_create(int bucketLen)
    {
        if (bucketLen < mBucketLen)
        {
            return false;
        }
        if (mHash)
        {
            MapTable<unsigned, _value> *tmp = new MapTable<unsigned, _value>[bucketLen];
            //GEN_Printf(LOG_DEBUG, "re create: %d, %d", bucketLen, mBucketLen);

            for (int i = 0; i < mBucketLen; ++i)
            {
                typename MapTable<unsigned, _value>::iterator it = mHash[i].begin();
                for (; it != mHash[i].end(); ++it)
                {
                    unsigned key    = it->key;
                    unsigned index  = key % bucketLen;

                    tmp[index][key] = it->value;
                    //GEN_Printf(LOG_DEBUG, "value[%#x]=%d %s", key, index, it->value.string());
                }
            }
            delete [] mHash;
            mHash = tmp;
        } else
        {
            mHash = new MapTable<unsigned, _value>[bucketLen];
        }

        mBucketLen = bucketLen;

        return true;
    }

    MapTable<unsigned, _value>   *mHash;
    int                           mBucketLen;
};

//! 这个容器存储了key和value值，所以使用者必须确保key和value的内存不被释放，
template <typename _key, typename _value>
class HashContainerEx
{
public:
    HashContainerEx(int size)
        : mHash(new MapTable<_key, _value>[size])
        , mBucketLen(size)
    {
    }
    ~HashContainerEx()
    {
        delete [] mHash;
    }

    void clear()
    {
        for (int i = 0; i < mBucketLen; i++)
        {
            mHash[i].clear();
        }
    }

    bool isExist(_key const &key)
    {
        unsigned ikey  = key.genHashValue();
        unsigned index = ikey % mBucketLen;

        if (mHash[index].empty())
        {
            return false;
        } else
        {
            typename MapTable<_key, _value>::iterator it = mHash[index].begin();
            for (; it != mHash[index].end(); ++it)
            {
                if (it->key == key)
                {
                    return true;
                }
            }
            return false;
        }
    }

    void insert(_key const &key, _value const &val)
    {
        unsigned ikey  = key.genHashValue();
        unsigned index = ikey % mBucketLen;

        // 如果最大单链数量超过4个就必须重新排列hash表
        if (4 == mHash[index].size())
        {
            //GEN_Printf(LOG_WARN, "Need rearrange hash container.", mHash[index].size());
            re_create(mBucketLen * 1.3);
            index = ikey % mBucketLen;
        }

        mHash[index][key] = val;
    }

    bool remove(_key const &key)
    {
        unsigned ikey  = key.genHashValue();
        unsigned index = ikey % mBucketLen;
        return mHash[index].remove(key);
    }

    _value &operator[] (_key const &key)
    {
        unsigned ikey  = key.genHashValue();
        unsigned index = ikey % mBucketLen;

        // 如果最大单链数量超过4个就必须重新排列hash表
        if (4 == mHash[index].size())
        {
            re_create(mBucketLen << 1);
            index = ikey % mBucketLen;
        }

        return mHash[index][key];
    }

    MapTable<_key, _value> &at(int index)
    {
        return mHash[index];
    }

    int bucketLen() const
    {
        return mBucketLen;
    }

    void swap(HashContainerEx &hash)
    {
        MapTable<_key, _value> *a = hash.mHash ;
        int                     b = hash.mBucketLen ;

        hash.mHash = mHash;
        hash.mBucketLen = mBucketLen;

        mHash = a;
        mBucketLen = b;
    }
private:
    HashContainerEx(HashContainerEx &);
    HashContainerEx &operator=(HashContainerEx &);

    bool re_create(int bucketLen)
    {
        if (bucketLen < mBucketLen)
        {
            return false;
        }
        if (mHash)
        {
            MapTable<_key, _value> *tmp = new MapTable<_key, _value>[bucketLen];

            for (int i = 0; i < mBucketLen; ++i)
            {
                typename MapTable<_key, _value>::iterator it = mHash[i].begin();
                for (; it != mHash[i].end();)
                {
                    unsigned key    = it->key.genHashValue();
                    unsigned index  = key % bucketLen;

                    typename MapTable<_key, _value>::iterator moveIt = it;
                    ++it;
                    mHash[i].move(moveIt, tmp[index]);

                    // tmp[index][it->key] = it->value;
                }
            }
            delete [] mHash;
            mHash = tmp;
        } else
        {
            mHash = new MapTable<_key, _value>[bucketLen];
        }

        mBucketLen = bucketLen;

        return true;
    }

    MapTable<_key, _value> *mHash;
    int                     mBucketLen;
};

#endif // HASH_CONTAINER_H
